阅读更多

21顶
0踩

研发管理

转载新闻 Java程序员们最常犯的10个错误

2014-06-25 10:32 by 见习记者 tianxiataguo 评论(14) 有34188人浏览
1.将数组转化为列表

将数组转化为一个列表时,程序员们经常这样做:

List<String> list = Arrays.asList(arr);

Arrays.asList()会返回一个ArrayList对象,ArrayList类是Arrays的一个私有静态类,而不是java.util.ArrayList类,java.util.Arrays.ArrayList类有set()、get()、contains()方法,但是没有增加元素的方法,所以它的大小是固定的,想要创建一个真正的ArrayList类,你应该这样做:

ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));

ArrayList的构造方法可以接受一个集合类型,刚好它也是java.util.Arrays.ArrayList的超类。

2.判断一个数组是否包含一个值

程序员们经常这样做:

Set<String> set = new HashSet<String>(Arrays.asList(arr)); 
return set.contains(targetValue);

这段代码起作用,但是没有必要把一个数组转化成列表,转化为列表需要额外的时间。它可以像下面那样简单:

Arrays.asList(arr).contains(targetValue);

或者是:

for(String s:arr){
    if(s.equals(targetValue)){
        return true;
    }
}
return false;

第一种方法比第二种更容易读

3.在一个循环中删除一个列表中的元素

思考下面这一段在循环中删除多个元素的的代码

ArrayList<String> list = new ArrayList<String>(Arrays.asList("a","b","c","d"));
for(int i=0;i<list.size();i++){
    list.remove(i);
}
System.out.println(list);

输出结果是:

[b,d]

在这个方法中有一个严重的错误。当一个元素被删除时,列表的大小缩小并且下标变化,所以当你想要在一个循环中用下标删除多个元素的时候,它并不会正常的生效。

你也许知道在循环中正确的删除多个元素的方法是使用迭代,并且你知道java中的foreach循环看起来像一个迭代器,但实际上并不是。考虑一下下面的代码:

ArrayList<String> list = new ArrayList<String>(Arrays.asList("a","b","c","d"));
for(String s:list){
    if(s.equals("a")){
        list.remove(s);
    }
}

它会抛出一个ConcurrentModificationException异常。

相反下面的显示正常:

ArrayList<String> list = new ArrayList<String>(Arrays.asList("a","b","c","d"));
Iterator<String> iter = list.iterator();
while(iter.hasNext()){
        String s = iter.next();
        if(s.equals("a")){
            iter.remove();
    }
}

.next()必须在.remove()之前调用。在一个foreach循环中,编译器会使.next()在删除元素之后被调用,因此就会抛出ConcurrentModificationException异常,你也许希望看一下ArrayList.iterator()的源代码。

4.Hashtable与HashMap的对比

就算法而言,哈希表是数据结构的一个名字。但是在java中,这个数据结构的名字是HashMap。Hashtable与HashMap的一个重要不同点是Hashtable是同步的。所以你经常不需要Hashtable,相反HashMap经常会用到。

具体请看:

5.在集合中使用原始类型

在Java中原始类型与无界通配符类型很容易混合在一起,拿Set来说,Set是一个原始类型,而Set<?>是无界的通配符类型。
考虑下面使用原始类型List作为参数的代码:

public static void add(List list,Object o){
    list.add(o);
}
pulbic static void main(String[] args){
    List<String> list = new ArrayList<String>();
    add(list,10);
    String s = list.get(0);

这段代码会抛出一个异常:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

    at ...

使用原生类型集合是危险的,这是因为原生类型集合跳过了泛型类型检查,并且不是安全的,在Set、Set<?>和Set<Object>中有很大的不同,具体请看Raw type vs. Unbounded wildcardType Erasure

6.访问级别

程序员们经常使用public作为类字段的修饰符,可以很简单的通过引用得到值,但这是一个坏的设计,按照经验,分配给成员变量的访问级别应该尽可能的低。

具体请看:public, default, protected, and private

7.ArrayList与LinkedList的对比

当程序员们不知道ArrayList与LinkedList的区别时,他们经常使用ArrayList,因为它看起来比较熟悉。然而,它们之前有巨大的性能差别。简而言之,如果有大量的增加删除操作并且没有很多的随机访问元素的操作,应该首先LinkedList。如果你刚接触它们,请查看ArrayList vs. LinkedList来获得更多关于它们性能的信息。

8.可变与不可变

不可变对象有许多的优点,比如简单,安全等等。但是对于每一个不同的值都需要一个独立的对象,太多的对象可能会造成大量的垃圾回收。当选择可变与不可变时应该有一个平衡。
一般的,可变对象用来避免产生大量的中间对象。一个典型的例子是连接大量的字符串。如果你用一个不可变的字符串,你会产生很多需要进行垃圾回收的对象。这很浪费CPU的时间,使用可变对象是正确的解决方案(比如StringBuilder)。

String result="";
for(String s: arr){
    result = result + s;
}

有时在某些情况下也是需要可变对象的,比如将可变对象作为参数传入方法,你不用使用很多语句便可以得到多个结果。另外一个例子是排序和过滤:当然,你可以写一个方法来接收原始的集合,并且返回一个排好序的集合,但是那样对于大的集合就太浪费了。(来自StackOverFlow的dasblinkenlight’s的答案)

具体请看:Why String is Immutable?

9.父类与子类的构造函数



这个编译期错误的出现是父类默认的构造方法未定义,在java中,如果一个类没有定义构造方法,编译器会默认的为这个类添加一个无参的构造方法。如果在父类中定义了构造方法,在这个例子中是Super(String s),编译器就不会添加默认的无参构造方法,这就是上面这个父类的情形。

子类的构造器,不管是无参还有有参,都会调用父类的无参构造器。因为编译器试图在子类的两个构造方法中添加super()方法。但是父类默认的构造方法未定义,编译器就会报出这个错误信息。

想要修复这个问题,可以简单的通过1)在父类中添加一个Super()构造方法,像下面这样:

public Super(){
    System.out.println("Super");
}

或者2)移除父类自定义的构造方法,或者3)在子类的构造方法中调用父类的super(value)方法。

具体请看:Constructor of Super and Stub

10.使用"   "还是构造器

有两种方式可以创建字符串:

//1.使用字符串
String x = "abc";
//2.使用构造器
String y = new String("abc");

有什么区别?

下面的例子会给出一个快速的答案:

String a = "abc";
String b = "abc";
System.out.println(a==b);//true
System.out.println(a.equals(b));//true
 
String c = new String("abc");
String d = new String("abc");
System.out.println(a==b);//false
System.out.println(a.equals(b));//true

关于它们内存分配的更多信息,请参考Create Java String Using ” ” or Constructor?.

将来的工作

这个列表是我基于大量的github上的开源项目,Stack overflow上的问题,还有一些流行的google搜索的分析。没有明显示的评估证明它们是前10,但它们绝对是很常见的。如果您不同意任一部分,请留下您的评论。如果您能提出其它一些常见的错误,我将会非常感激。

原文链接: programcreek 翻译: ImportNew.com - 林林
译文链接: http://www.importnew.com/12074.html
  • 大小: 27.2 KB
来自: ImportNew
21
0
评论 共 14 条 请登录后发表评论
14 楼 ayanami001 2015-06-29 17:53
ylxg12345 写道
最后那段比较的  
String c = new String("abc"); 
String d = new String("abc"); 
System.out.println(a==b);//false 
System.out.println(a.equals(b));//true 

望修改!



不要在意那些细节
13 楼 ylxg12345 2014-07-07 14:45
最后那段比较的  
String c = new String("abc"); 
String d = new String("abc"); 
System.out.println(a==b);//false 
System.out.println(a.equals(b));//true 

望修改!
12 楼 cbyyni 2014-07-04 14:14
        
11 楼 kidneyball 2014-07-04 07:59
mfkvfn 写道
第2个。for循环查找比转换为List然后调用contains好。
第3个可以用for循环(从后往前循环)来删除元素。


第2个,其实用Array.asList来wrap一下并不会损耗什么性能(参考第1点,Array.asList返回的是一个固定长度的List,直接把所有list操作代理到原本的数组上了)。而使用Array.asList返回的List来查找正确处理了null值的情况:

        public int indexOf(Object o) {
            if (o==null) {
                for (int i=0; i<a.length; i++)
                    if (a[i]==null)
                        return i;
            } else {
                for (int i=0; i<a.length; i++)
                    if (o.equals(a[i]))
                        return i;
            }
            return -1;
        }

        public boolean contains(Object o) {
            return indexOf(o) != -1;
        }


文中的简单循环在数组里有null值时会抛NPE的。
10 楼 lvwenwen 2014-07-03 11:31
总结得挺好
9 楼 bluky999 2014-07-02 13:38
10.

String c = new String("abc"); 
String d = new String("abc"); 
System.out.println(c==d);//false 
System.out.println(c.equals(d));//true


a->c
b->d
8 楼 fengjianquan9527 2014-06-30 12:27
7 楼 liuxmi 2014-06-29 19:34
凉风suzukaze 写道
o_o_0 写道
Integer a = 1;
Integer b = 1;
System.out.println(a==b);//true

Integer c = 200;
Integer d = 200;
System.out.println(c==d);//false

这是Integer类的缓存问题,一般开发中不怎么用得到吧~


对象类型比较统一用equals方法,只有初学者才会用==来比较
6 楼 凉风suzukaze 2014-06-28 15:19
o_o_0 写道
Integer a = 1;
Integer b = 1;
System.out.println(a==b);//true

Integer c = 200;
Integer d = 200;
System.out.println(c==d);//false

这是Integer类的缓存问题,一般开发中不怎么用得到吧~
5 楼 o_o_0 2014-06-28 11:32
Integer a = 1;
Integer b = 1;
System.out.println(a==b);//true

Integer c = 200;
Integer d = 200;
System.out.println(c==d);//false
4 楼 wussrc 2014-06-27 13:29
写的非常好,平常开发中确实没有注意过这些细节问题。
3 楼 shadowlin 2014-06-26 09:53
mfkvfn 写道
第2个。for循环查找比转换为List然后调用contains好。
第3个可以用for循环(从后往前循环)来删除元素。


还是用迭代器保险一点
2 楼 operating...mydream 2014-06-26 08:45
总结得挺好的LZ get
1 楼 mfkvfn 2014-06-25 11:56
第2个。for循环查找比转换为List然后调用contains好。
第3个可以用for循环(从后往前循环)来删除元素。

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • Java程序员们最常犯的10个错误.docx

    Java面试经验

  • Java程序员们最常犯的十个错误

    往往,我们在编程过程中都会碰到一些错误,从而造成一连串的反应,这里,汇总了十大程序员最容易犯的错误,与大家共勉!

  • Java程序员常犯的五个错误

    总结以前经验针对java编程的一些习惯,给出一些关于java编程的建议: 当你开始成为一个程序员的时候,在编程的时候很容易陷入下面所述的一些坏习惯,下面把Java程序员常犯的五个错误整理如下,需要的朋友可以参考下

  • Java程序员最常犯的10个错误

    那么对于广大的Java程序员来说,它们最常犯的10个错误是什么呢?本文通过总结出Java程序员最常犯的10大错误,可以有效地帮组Java后来者少走弯路,少加班,并写出更健壮的应用程序。1数组转ArrayList为了实现把一个...

  • Java程序员常犯的10个错误

    那么对于广大的Java程序员来说,它们最常犯的10个错误是什么呢?本文是动力节点java学院小编总结的Java程序员最常犯的10大错误,可以有效的帮助Java后来者少走弯路,少加班,并写出更健壮的应用程序。1、访问级别...

  • Java程序员容易犯的10大低级错误

    主要介绍了Java程序员容易犯的10大低级错误,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下

  • Java程序员们最常犯的3个集合错误

    Java程序员们最常犯的3个集合错误   1、将数组转化为列表 将数组转化为一个列表时,程序员们经常这样做: List list = Arrays.asList(arr); Arrays.asList() 会返回一个ArrayList对象,ArrayList类是Arrays的...

  • Java 程序员容易犯的10个SQL错误

    本文介绍了Java 程序员容易犯的10个SQL错误。具有很好的参考价值,下面跟着小编一起来看下吧

  • 对于一名Java程序员来说 常犯的错误都有哪些

    那么对于广大的Java程序员来说,他们​常犯的错误是什么呢?下面一起来看一下吧! 1.Duplicated Code 代码重复可谓是十分常见的问题了。他也是Refactoring的主要目标之一。代码重复往往来自于copy-and-paste的编程...

  • Java程序员容易犯的10个错误

    Java程序员容易犯的10个错误,Arrays.asList() 会返回一个ArrayList,这是Arrays里内嵌的一个私有静态类,而并不是java.util.ArrayList类java.util.Arrays.ArrayList 有set(), get(), contains()方法,但并支持添加...

  • java程序员最头疼的十大问题_Java程序员最常犯的错误盘点之Top 10

    那么对于广大的Java程序员来说,它们最常犯的10个错误是什么呢?本文通过总结出Java程序员最常犯的10大错误,可以有效地帮组Java后来者少走弯路,少加班,并写出更健壮的应用程序。1. 数组转Arr...

  • 饕餮族北京之选(六)

    饕餮族北京之选(六)1. 鹭鹭: 上海菜, 上海一著名餐厅的分号, 在北京有两家店, 俺只去位于红庙那一家. 历年来一直将八宝辣酱做特价. 比起上海来说可能味道差些, 但在北京,俺个人 认为比夜上海之流强得不是一星半点. 菜品质量比较平均, 特别是毛蟹炒年糕很好但实在很贵, 总体价位不便宜, 需订位. 电话: 65930442. 地址在大望路, 即红庙路口向南一点儿即是.2. 静颐洲: 味道差鹭鹭

  • 饕餮族北京之选(二)

    饕餮族北京之选(二)从东三环国贸向北,一直延伸到三元西桥附近,是北京美食的中心,在这一区域中有各种档次的各种风味的美食,不少美食潮流就是从这里开始的。  在国贸地区,皇城老妈是四川火锅的代表之一,与一般四川火锅的平民化相比,皇城老妈走的是高档火锅路线,对环境、对菜品档次都非常注意。在中服大厦二楼,金山城重庆菜是这一地方最有名的餐厅,无论是泡椒系列、糊辣系列、各种烧菜,还是毛血旺以及各种四川小吃都让

  • 饕餮族北京之选(四)

    饕餮族北京之选(四)   用了一上午的工夫,重新梳理了一下那张“美食地图”,把地址不详的删掉,太多的废话删掉,雷同的删掉……最后呈现给大家的是下面这份“美食宝典”,大家可以按图索骥,去找自己想吃的东东了~~祝大家胃口好   小吃:   1热干面 新街口的稻香春门脸,有个小小小小小极了的四川小吃店里的热干面一绝,好像只要两元五哟~~~~~   2锅贴 从地百北边的胡同串向后海,中途会有个小店,里面的

  • 中国发展3G尚需解决的几大问题

    尽管“跨过3G上4G”的言论正鼓动着一部分人,但从中国的国情来看,3G仍是中国移动通信产业不可逾越的发展阶段。诚然,目前还有许多问题需要解决,但这些大多是发展中的问题,不应成为中国发展3G产业的桎梏,因此发展3G乃大势所趋。 前不久,沃达丰在德国和葡萄牙正式推出用3G业务,欧洲已有许多国家实现了3G商用,即使在亚洲,日本及韩国的3G发展也取得了不小的成绩。在此背景下,有关中国3G何时启动的问题再度

  • 互动式语音应答业务IVR能否续写短信神话

    短信的发展创造了一个通信业的奇迹,无论是运营商还是SP,无时无刻不在寻找着继短信之后的另一"杀手"级业务。2004年,人们把目光不约而同地聚焦到了IVR上。   IVR(Interactive Voice Response)即互动式语音应答业务,是中国移动早在2002年底就推出的一项业务。由于种种原因,IVR一直到今年初才出现在新浪、搜狐等公司的网页上,并且发展速度之快引起了业界的关注。   与短

  • 饕餮族北京之选(五)

    饕餮族北京之选(五)一、水煮鱼1、大阿福水煮鱼餐厅,朝阳区三里屯北14楼,消费水平30-50元,水煮鱼:82元/份。2、花诚酒家,外馆斜街,辣嘴不辣喉咙!香,18元儿一斤!3、辣婆婆水煮鱼店,沙滩后街47号(丽都饭店对面另一家),启用御仁舫和富丽的雅号,4、“皇阿婆”, 西直门外北下关里,北方交大南门外,5、渝信川菜,工体北路幸福一村,价钱贵了点,48/盆,一整条鱼为一份!6、红京鱼餐厅(原先是在

  • 安装NumPy教程-详细版

    附件是安装NumPy教程_详细版,文件绿色安全,请大家放心下载,仅供交流学习使用,无任何商业目的!

Global site tag (gtag.js) - Google Analytics